package com.better.common.jwtauth.auth;


import com.better.backend.mqReceiverService.UserInfo.model.UserModel;
import com.better.backend.mqReceiverService.UserInfo.repository.UserInfoRepsitory;
import com.better.common.base.ServiceResponse;
import com.better.common.jwtauth.TokenManager.RedisTokenManager;
import com.better.common.jwtauth.secruity.*;
import com.better.common.jwtauth.user.UserRepository;
import com.better.common.utils.Encodes;
import com.better.common.utils.ServiceResponseHandle;
import com.better.common.utils.redis.RedisUtils;
import com.better.common.utils.serc.Digests;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static java.util.Arrays.asList;

@Service
public class AuthServiceImpl implements AuthService {

    private AuthenticationManager authenticationManager;
    private JwtUserDetailsService userDetailsService;
    private JwtTokenUtil jwtTokenUtil;
    private UserRepository userRepository;
    private UserInfoRepsitory userInfoRepsitory;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private RedisTokenManager redisTokenManager;
    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    public AuthServiceImpl(
            AuthenticationManager authenticationManager,
            JwtUserDetailsService userDetailsService,
            JwtTokenUtil jwtTokenUtil,
            UserRepository userRepository, UserInfoRepsitory userInfoRepsitory) {
        this.authenticationManager = authenticationManager;
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.userRepository = userRepository;
        this.userInfoRepsitory = userInfoRepsitory;
    }

    @Override
    public UserModel register(UserModel userToAdd) {
        String username = userToAdd.getLoginName();
        if (userInfoRepsitory.findByLoginName(username) != null) {
            return null;
        }
        // BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String rawPassword = userToAdd.getPassword();
        MyPasswordEncode encoder = new MyPasswordEncode();
        // userToAdd.setPassword(EncryptUtils.entryptPassword(rawPassword));
        userToAdd.setPassword(encoder.encode(rawPassword));
        userToAdd.setLastPasswordResetDate(new Date());
        userToAdd.setRoles(asList("ROLE_USER"));
        return userInfoRepsitory.insert(userToAdd);
    }

    @Override
    public JwtAuthenticationResponse login(String username, String password) {
        //EncryptUtils.entryptPassword(password)
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
        Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        JWTUserDetails userDetails = (JWTUserDetails) userDetailsService.loadUserByUsername(username);
        //String token = jwtTokenUtil.generateAccessToken(userDetails);
        String token = redisTokenManager.generateAccessToken(userDetails);
        JwtAuthenticationResponse response = new JwtAuthenticationResponse(token, userDetails);
        return response;
    }

    @Override
    public String refresh(String oldToken) {
        String token = oldToken.substring(tokenHead.length());
        String username = jwtTokenUtil.getUsernameFromToken(token);
        if (StringUtils.isEmpty(username)) return null;
        JWTUserDetails user = (JWTUserDetails) userDetailsService.loadUserByUsername(username);
        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
            return jwtTokenUtil.refreshToken(token);
        }
        return null;
    }

    private final String ssoLoginAuthRandomKey = "sso:userloginauth:random";
    private static final int HASH_INTERATIONS = 1024;
    private static final int SALT_SIZE = 8;

    @Override
    public ServiceResponse getSaltByUname(String userName) {
        //byte[] salt = Digests.generateSalt(SALT_SIZE);
        UserModel userInfo=userInfoRepsitory.findByLoginName(userName);
        if (userInfo== null) {
            return ServiceResponseHandle.failed("用户不存在！");
        }
        byte[] salt = Encodes.decodeHex(userInfo.getPassword().substring(0, 16));
        String hexSalt=Encodes.encodeHex(salt);
        Map<String, Object> saltMap = new HashMap<String, Object>();
        saltMap.put("salt", hexSalt);
        String r = this.getRandomString(8);
        saltMap.put("r", r);
        redisUtils.set(ssoLoginAuthRandomKey + ":" + userName, r, 60);
        return ServiceResponseHandle.success(saltMap);
    }

    /**
     * 生成指定长度的随机字符串
     *
     * @param length 表示生成字符串的长度
     * @return
     */
    private String getRandomString(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}
